package com.ruyuan.engine.router;
import com.ruyuan.engine.pojo.ClientLog;
import com.ruyuan.engine.pojo.CombinationRuleParam;
import com.ruyuan.engine.pojo.RuleComplexParam;
import com.ruyuan.engine.pojo.RuleEventExecuteParam;
import com.ruyuan.engine.service.ClickHouseServer;
import com.ruyuan.engine.utils.ClickHouseUtils;
import com.ruyuan.engine.utils.Configuration;
import com.ruyuan.engine.utils.HBaseUtils;
import com.ruyuan.engine.utils.RuleCommonProcessUtils;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.flink.api.common.state.ListState;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.hadoop.hbase.client.Connection;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 第三版查询的RouterService
 * */
@Slf4j
public class RouterService {
    ClickHouseServer clickHouseServer;
    HBaseSearchService hBaseSearchService;
    FLinkStateService fLinkStateService;

    public RouterService(ListState<ClientLog> listState) throws Exception {
        Config config = ConfigFactory.load();
        clickHouseServer = new ClickHouseServer(ClickHouseUtils.getConnection());
        Connection hbaseConnection = HBaseUtils.getConnection();
        String tableName = config.getString(Configuration.HBASE_TABLE_NAME);
        String columnFamily = config.getString(Configuration.HBASE_CLOUMN_FAMILY);
        hBaseSearchService = new HBaseSearchService(hbaseConnection,tableName,columnFamily);
        fLinkStateService = new FLinkStateService(listState);
    }

    /**
     * 基础规则匹配
     * */
    public boolean matchBaseRuleCondition(Map<String,String> mapConditions,String userId) throws Exception {
        return hBaseSearchService.matchBaseRuleCondition(mapConditions,userId);
    }

    /**
     * 计算行为组合规则是否匹配
     * */
    public boolean mathRuleCombinationCondition(CombinationRuleParam combinationRuleParam,ClientLog clientLog) throws Exception {
        //获取缓存有效的时间段
        long timeLimit = RuleCommonProcessUtils.splitTime(clientLog.getDetailTime());
        long startTime = combinationRuleParam.getStartTime();
        long endTime = combinationRuleParam.getEndTime();
        String userNo = clientLog.getUserNo();

        /**
         * 查询Flink状态缓存数据
         * */
        if (startTime >= timeLimit) {
            int count = fLinkStateService.combinationMatchCount(combinationRuleParam, startTime, endTime);
            return count >= combinationRuleParam.getMinCount() && count <= combinationRuleParam.getMaxCount();
        }else if(endTime < timeLimit) {
            /**
             * 查询clickHouse
             * //需要返回结果，在分段查询的时候利用。
             * 如果只查询clickhouse，不需要分段查询，直接调用mathRuleCombinationConditionCountByFalse方法
             * */
            Tuple2<String, Integer> stringIntegerTuple2 = clickHouseServer.mathRuleCombinationConditionCountByFalse(userNo, combinationRuleParam, startTime, endTime);
            log.debug("组合规则条件id：{} 在clickhouse中查询，开始时间为{}， 结束时间为{},结果为{}",combinationRuleParam.getCacheId(),startTime,endTime,stringIntegerTuple2.f1);
            //判断clickhouse查询结果与阈值进行比较
            return stringIntegerTuple2.f1 >= combinationRuleParam.getMinCount() && stringIntegerTuple2.f1 <= combinationRuleParam.getMaxCount();
        }else {
            //分段查询,fLinkStateService
            int count = fLinkStateService.combinationMatchCount(combinationRuleParam, timeLimit, endTime);
            log.debug("组合规则条件id：{} 分段在fLinkStateService中查询，开始时间为{}， 结束时间为{},结果为{}",combinationRuleParam.getCacheId(),timeLimit,endTime,count);
            if (count >= combinationRuleParam.getMinCount()) return true;


            /**
             * 查询clickhouse，flag设置为true，需要获取完整的查询结果
             * */
            Tuple2<String, Integer> stringIntegerTuple2 = clickHouseServer.mathRuleCombinationConditionCount(userNo, combinationRuleParam, startTime, timeLimit, true);
            //clickhouse中是否满足条件
            log.debug("组合规则条件id：{} 分段在clickHouse中查询，开始时间为{}， 结束时间为{},结果为{}",combinationRuleParam.getCacheId(),startTime,timeLimit,stringIntegerTuple2.f1);
            if (stringIntegerTuple2.f1 >= combinationRuleParam.getMinCount()) return true;

            /**
             * 拼接clickhose和fLinkStateService结果进行匹配
             * */
            String combinationCountByState = fLinkStateService.getCombinationCountByState(combinationRuleParam, timeLimit, endTime);
            int clickHouseAndStateCount = RuleCommonProcessUtils.sequenceMathCountByRegex(stringIntegerTuple2.f0 + combinationCountByState, combinationRuleParam.getRegexp());
            log.debug("组合规则条件id：{} 在clickhouse和state进行组合查询，开始时束间为{}， 结时间为{}, clickhouse结果为{},flinkState结果为{},最终匹配结果为 {}",combinationRuleParam.getCacheId(),startTime,endTime,stringIntegerTuple2.f0,combinationCountByState,clickHouseAndStateCount);
            //判断是否匹配成功
            return clickHouseAndStateCount >= combinationRuleParam.getMinCount() && clickHouseAndStateCount <= combinationRuleParam.getMaxCount();
        }
    }

    /**
     * 通过isMatch方法整合所有查询的逻辑
     * */
    public Boolean isMatch(RuleComplexParam ruleComplexParam,ClientLog clientLog) throws Exception {
        //当前事件是否满足触发条件
        RuleEventExecuteParam trigger = ruleComplexParam.getTrigger();
        if (!RuleCommonProcessUtils.eventMatchRuleParam(clientLog,trigger)) {
            return false;
        }
        log.debug("规则编号：{}，事件类型：{}，满足了触发条件",ruleComplexParam.getRuleId(),clientLog.getEventId());

        //基本规则条件判断
        HashMap<String, String> baseRuleParams = ruleComplexParam.getBaseRuleParams();
        if (baseRuleParams !=null && baseRuleParams.size() > 0) {
            boolean result = matchBaseRuleCondition(baseRuleParams, clientLog.getUserNo());
            log.debug("规则编号：{}，基本规则匹配结果为：{}",ruleComplexParam.getRuleId(),result);
            if (!result) return false;
        }

        //组合规则条件判断
//        ruleComplexParam.getCombinationRuleParams()之前的实现方案
        /**
         * 使用现在合并以后的方案
         * */
        List<CombinationRuleParam> combinationRuleList = ruleComplexParam.getCombinationRuleList();
        if (combinationRuleList !=null && combinationRuleList.size() >0) {
            for(CombinationRuleParam combinationRuleParam:combinationRuleList) {
                boolean result = mathRuleCombinationCondition(combinationRuleParam, clientLog);
                log.debug("规则编号：{}，组合规则匹配结果为：{}",ruleComplexParam.getRuleId(),result);
                if (!result) return false;
            }
        }
        return true;
    }

    /**
     * 检查定时条件是否满足
     * */
}
